package com.ikingtech.platform.service.tenant.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikingtech.framework.sdk.base.model.PageResult;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.enums.system.tenant.TenantStatusEnum;
import com.ikingtech.framework.sdk.tenant.model.TenantQueryParamDTO;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.service.tenant.entity.TenantDO;
import com.ikingtech.platform.service.tenant.exception.TenantExceptionInfo;
import com.ikingtech.platform.service.tenant.mapper.TenantMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author tie yan
 */
@Slf4j
@Service
@AllArgsConstructor
public class TenantService extends ServiceImpl<TenantMapper, TenantDO> {

    public void checkStatusAndPeriod(TenantDO entity) {
        if (TenantStatusEnum.NORMAL.name().equals(entity.getStatus()) &&
                null != entity.getStartDate() &&
                entity.getStartDate().isAfter(LocalDate.now())) {
            // 当前状态正常，指定了开始时间
            // 开始时间晚于当前时间，当前状态不能为正常
            throw new FrameworkException(TenantExceptionInfo.INVALID_START_DATE_WITH_NORMAL_STATUS);
        }
        if (TenantStatusEnum.NORMAL.name().equals(entity.getStatus()) &&
                null != entity.getEndDate() &&
                entity.getEndDate().isBefore(LocalDate.now())) {
            // 当前状态正常，指定了结束时间
            // 结束时间早于当前时间，当前状态不能为正常
            throw new FrameworkException(TenantExceptionInfo.INVALID_END_DATE_WITH_NORMAL_STATUS);
        }
        if (TenantStatusEnum.FREEZE.name().equals(entity.getStatus()) &&
                null != entity.getStartDate() &&
                null != entity.getEndDate() &&
                !entity.getStartDate().isAfter(LocalDate.now())) {
            // 当前状态冻结，指定了开始时间和结束时间
            // 开始时间早于或等于当前时间，结束时间晚于或等于当前时间，当前状态不能为冻结
            throw new FrameworkException(TenantExceptionInfo.INVALID_END_DATE_WITH_NORMAL_STATUS);
        }
    }

    public PageResult<TenantDO> listPage(TenantQueryParamDTO queryParam) {
        return PageResult.build(this.page(new Page<>(queryParam.getPage(), queryParam.getRows()), Wrappers.<TenantDO>lambdaQuery()
                .like(Tools.Str.isNotBlank(queryParam.getName()), TenantDO::getName, queryParam.getName())
                .like(Tools.Str.isNotBlank(queryParam.getCode()), TenantDO::getCode, queryParam.getCode())
                .eq(Tools.Str.isNotBlank(queryParam.getType()), TenantDO::getType, queryParam.getType())
                .like(Tools.Str.isNotBlank(queryParam.getTenantDomain()), TenantDO::getTenantDomain, queryParam.getTenantDomain())
                .eq(Tools.Str.isNotBlank(queryParam.getStatus()), TenantDO::getStatus, queryParam.getStatus())
                .ge(queryParam.getCreateTimeStartDate() != null && queryParam.getCreateTimeEndDate() == null, TenantDO::getCreateTime, null == queryParam.getCreateTimeStartDate() ? null : LocalDateTime.of(queryParam.getCreateTimeStartDate(), LocalTime.of(0, 0, 0)))
                .le(queryParam.getCreateTimeStartDate() == null && queryParam.getCreateTimeEndDate() != null, TenantDO::getCreateTime, null == queryParam.getCreateTimeEndDate() ? null : LocalDateTime.of(queryParam.getCreateTimeEndDate(), LocalTime.of(23, 59, 59)))
                .between(queryParam.getCreateTimeStartDate() != null && queryParam.getCreateTimeEndDate() != null, TenantDO::getCreateTime, null == queryParam.getCreateTimeStartDate() ? null : LocalDateTime.of(queryParam.getCreateTimeStartDate(), LocalTime.of(0, 0, 0)), null == queryParam.getCreateTimeEndDate() ? null : LocalDateTime.of(queryParam.getCreateTimeEndDate(), LocalTime.of(23, 59, 59)))
                .ge(queryParam.getUpdateTimeStartDate() != null && queryParam.getUpdateTimeEndDate() == null, TenantDO::getUpdateTime, null == queryParam.getUpdateTimeStartDate() ? null : LocalDateTime.of(queryParam.getUpdateTimeStartDate(), LocalTime.of(0, 0, 0)))
                .le(queryParam.getUpdateTimeStartDate() == null && queryParam.getUpdateTimeEndDate() != null, TenantDO::getUpdateTime, null == queryParam.getUpdateTimeEndDate() ? null : LocalDateTime.of(queryParam.getUpdateTimeEndDate(), LocalTime.of(23, 59, 59)))
                .between(queryParam.getUpdateTimeStartDate() != null && queryParam.getUpdateTimeEndDate() != null, TenantDO::getUpdateTime, null == queryParam.getUpdateTimeStartDate() ? null : LocalDateTime.of(queryParam.getUpdateTimeStartDate(), LocalTime.of(0, 0, 0)), null == queryParam.getUpdateTimeEndDate() ? null : LocalDateTime.of(queryParam.getUpdateTimeEndDate(), LocalTime.of(23, 59, 59)))
                .ge(queryParam.getStartTimeStartDate() != null && queryParam.getStartTimeEndDate() == null, TenantDO::getStartDate, queryParam.getStartTimeStartDate())
                .le(queryParam.getStartTimeStartDate() == null && queryParam.getStartTimeEndDate() != null, TenantDO::getStartDate, queryParam.getStartTimeEndDate())
                .between(queryParam.getStartTimeStartDate() != null && queryParam.getStartTimeEndDate() != null, TenantDO::getStartDate, queryParam.getStartTimeStartDate(), queryParam.getStartTimeEndDate())
                .ge(queryParam.getEndTimeStartDate() != null && queryParam.getEndTimeEndDate() == null, TenantDO::getEndDate, queryParam.getEndTimeStartDate())
                .le(queryParam.getEndTimeStartDate() == null && queryParam.getEndTimeEndDate() != null, TenantDO::getEndDate, queryParam.getEndTimeEndDate())
                .between(queryParam.getEndTimeStartDate() != null && queryParam.getEndTimeEndDate() != null, TenantDO::getEndDate, queryParam.getEndTimeStartDate(), queryParam.getEndTimeEndDate())
                .orderByDesc(TenantDO::getCreateTime)));
    }

    public TenantDO getByCode(String tenantCode) {
        return this.getOne(Wrappers.<TenantDO>lambdaQuery().eq(TenantDO::getCode, tenantCode));
    }

    public Integer getMaxSortOrder() {
        List<Number> orders = this.listObjs(Wrappers.<TenantDO>lambdaQuery()
                .select(TenantDO::getSortOrder)
                .orderByDesc(TenantDO::getSortOrder), Number.class::cast);
        return Tools.Coll.isBlank(orders) ? 0 : orders.get(0).intValue();
    }

    public boolean nameExist(String name) {
        return this.baseMapper.exists(Wrappers.<TenantDO>lambdaQuery()
                .isNull(TenantDO::getId)
                .eq(TenantDO::getName, name));
    }

    public boolean codeExist(String code) {
        return this.baseMapper.exists(Wrappers.<TenantDO>lambdaQuery()
                .isNull(TenantDO::getId)
                .eq(TenantDO::getCode, code));
    }

    public boolean nameExist(String id, String name) {
        return this.baseMapper.exists(Wrappers.<TenantDO>lambdaQuery()
                .ne(TenantDO::getId, id)
                .eq(TenantDO::getName, name));
    }

    public boolean codeExist(String id, String code) {
        return this.baseMapper.exists(Wrappers.<TenantDO>lambdaQuery()
                .ne(TenantDO::getId, id)
                .eq(TenantDO::getCode, code));
    }

    public void removeByCode(String tenantCode) {
        this.remove(Wrappers.<TenantDO>query().lambda().eq(TenantDO::getCode, tenantCode));
    }

    public List<TenantDO> listByCodes(List<String> codes) {
        if (Tools.Coll.isBlank(codes)) {
            return new ArrayList<>();
        }
        return this.list(Wrappers.<TenantDO>lambdaQuery().in(TenantDO::getCode, codes));
    }

    public boolean exist(String id) {
        return this.baseMapper.exists(Wrappers.<TenantDO>lambdaQuery().eq(TenantDO::getId, id));
    }

    public boolean existByCode(String code) {
        return this.baseMapper.exists(Wrappers.<TenantDO>lambdaQuery().eq(TenantDO::getCode, code));
    }
}
